package com.practice;

import lombok.extern.slf4j.Slf4j;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

@Slf4j
public class Account {

    Lock lock = new ReentrantLock();

    private int money;

    private final String name;

    public Account(int money, String name) {
        this.name = name;
        this.money = money;
    }

    public int getMoney() {
        lock.lock();
        try {
            return money;
        } finally {
            lock.unlock();
        }
    }

    public void setMoney(int money) {
        lock.lock();
        try {
            this.money = money;

        } finally {
            lock.unlock();
        }
    }

    public void transfer(Account target, int amount) {
        boolean success = false;

        try {
            while (!success) {

                boolean locked = lock.tryLock(2, TimeUnit.MILLISECONDS);

                if (locked) {
                    log.debug("获取到外层锁");
                    try {

                        Lock targetLock = target.getLock();

                        boolean targetLocked = targetLock.tryLock(2, TimeUnit.MILLISECONDS);

                        if (targetLocked) {
                            log.debug("获取到内层锁");
                            try {
                                if (this.money > amount) {
                                    this.setMoney(this.getMoney() - amount);
                                    target.setMoney(target.getMoney() + amount);
                                    log.debug("【{}】（有{}元）向【{}】（有{}元）转账【{}】元成功", this.name, this.getMoney(), target.getName(), target.getMoney(), amount);
                                } else {
                                    log.debug("【{}】剩余金额不足{}元，转账失败（需要转账{}元）", this.name, this.money, amount);
                                }
                                success = true;
                            } finally {

                                targetLock.unlock();
                                log.debug("内层锁已释放");
                            }
                        } else {
                            log.debug("内层锁超时，获取失败");

                        }
                    } finally {
                        lock.unlock();
                        log.debug("外层锁已释放");
                    }
                } else {
                    log.debug("外层锁超时，获取失败");
                }

                Thread.yield();


            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

    }


    public Lock getLock() {
        return this.lock;
    }

    public String getName() {
        return name;
    }
}
